///\file sizor.hh
///\brief contient les spécifications de la classe CUDA::Sizor
///\author { V.Allombert, A.Blanchard, A.Carteron, V.Pelletier } 

#ifndef _SIZOR
#define _SIZOR

#include <list>
#include "image.hh"
#include "gpu.hh"
#include "matrix.hh"
#include <iterator>

//FAIT A LA COMPILATION !!!!
#define MPS PHYSICAL_MPS*3
#define MAXMEM GPU_TOTAL_MEM/16
#define NB_THREADS PHYSICAL_NB_THREADS*3
#define SHARED_LENGTH 0x4000/(sizeof(pixel)*4*PHYSICAL_NB_THREADS)+1

namespace CUDA{

  ///\struct coord_data
  ///\brief coordonnées définissant les bords d'un bloc image
  struct coord_data{
    unsigned int bxi; ///< début de coordonnées, en x, de l'image d'entrée
    unsigned int byi; ///< début de coordonnées, en y, de l'image d'entrée
    unsigned int bxo; ///< début de coordonnées, en x, de l'image en sortie
    unsigned int byo; ///< début de coordonnées, en y, de l'image en sortie
    unsigned int wblock_in; ///< largeur du block en entrée
    unsigned int hblock_in; ///< hauteur du block en entrée
    unsigned int wblock_out; ///< largeur du block en sortie
    unsigned int hblock_out; ///< hauteur du block en sortie
  };

  ///\brief permet de paramétrer les getters pour obtenir les coordonnées voulus
  enum { IN , OUT };

  ///\class Sizor
  ///\brief Classe de découpage d'image
  class Sizor{
  private:
    std::list<coord_data> block_lst; ///< Liste des blocks
    std::list<coord_data>::iterator it; ///< Iterateur sur la position du prochaine élément à traiter
    unsigned int block_size; ///< taille maximale d'un block
    unsigned int wblock_in; ///< largeur maximale d'un block en entrée
    unsigned int hblock_in; ///< hauteur maximale d'un block en entrée
    unsigned int wblockmax_out; ///< largeur maximale d'un block en sortie
    unsigned int hblockmax_out; ///< hauteur maximale d'un block en sortie

  public:

    ///\brief Constructeur
    ///construit un objet de découpe d'image
    ///\param i image à découper
    ///\param m matrix de convolution
    Sizor(const Image &i, const Matrix<int> &m);

    ///\brief récupérer un chunk
    ///\return les données du chunk
    inline coord_data next(){
      return (*it++);
    }
    
    ///\brief Reste-t-il des chunks ?
    ///\return Chunk restant
    inline bool has_next(){
      return it!=block_lst.end();
    }

    ///\brief retourne la largeur du block courrant
    ///\param type de la demande (IN ou OUT)
    ///\return la largeur du block courrant
    inline unsigned int getCurrentWidth(int type){
      return type==IN? (*it).wblock_in : (*it).wblock_out ;
    }

    inline unsigned int getCurrentHeight(int type){
      return type==IN? (*it).hblock_in : (*it).hblock_out ;
    }

    inline unsigned int getMaxWidth(int type){
      return type==IN? wblock_in : wblockmax_out;
    }

    inline unsigned int getMaxHeight(int type){
      return type==IN? hblock_in : hblockmax_out;
    }

    inline coord_data current(){
      return (*it);
    }
  };

}
#endif
